package cc.zstart.generator.mybatis.util;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.mybatis.generator.exception.ShellException;
import org.mybatis.generator.internal.DomWriter;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;


/**
 * @desc <p></p>
 * @author DaiJiangGuo
 * @date 2015年5月17日下午3:25:41
 */
public class AmanDomWriter extends DomWriter {

    List<Element> elementList = new ArrayList<Element>();

    /**
     * @author DaiJiangGuo
     * @param doc
     * @data 2015年5月18日 上午11:14:00
     */
    public void initElementList(Node node) {
        if(node != null && node.getNodeType() == Node.ELEMENT_NODE){
            elementList.add((Element) node);
            NodeList list = node.getChildNodes();
            for(int i=0;i<list.getLength();i++){
                initElementList(list.item(i));
            }
        }
    }

    public static void main(String[] args) throws Exception {
        String s = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
                + "<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >"
                + "<mapper namespace=\"com.flow.mapper.BannerMapper\" >\n"+
                "  <resultMap id=\"BaseResultMap\" type=\"com.flow.entity.Banner\" >\n"+
                "    <result column=\"title\" property=\"title\" jdbcType=\"DATE\" />\n"+
                "    <result column=\"test_date2\" property=\"testDate2\" jdbcType=\"DATE\" />\n"+
                "  </resultMap>\n"+
                "</mapper>\n";
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setExpandEntityReferences(false);
        DocumentBuilder builder = factory.newDocumentBuilder();

        builder.setEntityResolver(new NullEntityResolver());
        InputSource is = new InputSource(new StringReader(s));
        Document existingDocument = builder.parse(is);
        AmanDomWriter dw = new AmanDomWriter();
        dw.initElementList(existingDocument.getDocumentElement());

        List<Element> el = dw.getElementList();
        AmanSaxWriter asw = new AmanSaxWriter();
        asw.parse(s, el);

        String source = dw.toString(existingDocument);
        System.out.println(source);
    }



    @Override
    protected void write(Document node) throws ShellException {
        isXML11 = "1.1".equals(getVersion(node)); //$NON-NLS-1$
        if (isXML11) {
            printWriter.println("<?xml version=\"1.1\" encoding=\"UTF-8\" ?>"); //$NON-NLS-1$
        } else {
            printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); //$NON-NLS-1$
        }
        printWriter.flush();
        write(node.getDoctype());
        write(node.getDocumentElement());
    }

    protected void write(DocumentType node) throws ShellException {
        printWriter.print("<!DOCTYPE "); //$NON-NLS-1$
        printWriter.print(node.getName());
        String publicId = node.getPublicId();
        String systemId = node.getSystemId();
        if (publicId != null) {
            printWriter.print(" PUBLIC \""); //$NON-NLS-1$
            printWriter.print(publicId);
            printWriter.print("\" \""); //$NON-NLS-1$
            printWriter.print(systemId);
            printWriter.print('\"');
        } else if (systemId != null) {
            printWriter.print(" SYSTEM \""); //$NON-NLS-1$
            printWriter.print(systemId);
            printWriter.print('"');
        }

        String internalSubset = node.getInternalSubset();
        if (internalSubset != null) {
            printWriter.println(" ["); //$NON-NLS-1$
            printWriter.print(internalSubset);
            printWriter.print(']');
        }
        printWriter.println(" >");
    }


    public static void getPath(Element e){
        Node parentNode = e.getParentNode();
        Element parentElement = null;
        if(parentNode.getNodeType() == Node.ELEMENT_NODE){
            parentElement = (Element) parentNode;
        }
        parentElement.getElementsByTagName(e.getTagName());
    }

    protected void write(Element node) throws ShellException {
        printWriter.print('<');
        printWriter.print(node.getNodeName());

        NamedNodeMap attrsMap = node.getAttributes();
        int len = (node.getAttributes() != null) ? node.getAttributes().getLength() : 0;
        List<Attr> attrs = new ArrayList<Attr>();

        String order = node.getAttribute("aman_attr_order");
        if(order != null && !"".equals(order)){
            String[] attrNames = order.split(":");
            for (int i = 0; i < attrNames.length; i++) {
                Attr attr = (Attr) attrsMap.getNamedItem(attrNames[i]);
                if(attr != null){
                    attrs .add(attr);
                }
            }
        }
        for (int i = 0; i < len; i++) {
            Attr attr = (Attr) attrsMap.item(i);
            if("aman_attr_order".equals(attr.getName())){
                continue;
            }
            if(!attrs.contains(attr)){
                attrs .add(attr);
            }
        }

        for (Attr attr : attrs) {
            printWriter.print(' ');
            printWriter.print(attr.getNodeName());
            printWriter.print("=\""); //$NON-NLS-1$
            normalizeAndPrint(attr.getNodeValue(), true);
            printWriter.print('"');
        }

        if (node.getChildNodes().getLength() == 0) {
            printWriter.print(" />"); //$NON-NLS-1$
            printWriter.flush();
        } else {
            printWriter.print(" >");
            printWriter.flush();

            Node child = node.getFirstChild();
            while (child != null) {
                writeAnyNode(child);
                child = child.getNextSibling();
            }

            printWriter.print("</"); //$NON-NLS-1$
            printWriter.print(node.getNodeName());
            printWriter.print('>');
            printWriter.flush();
        }
    }

    public List<Element> getElementList() {
        return elementList;
    }

    public void setElementList(List<Element> elementList) {
        this.elementList = elementList;
    }


}
